import util
import yaml
import time
from action import Action
from eventServer import eventServer

class Object:
    allObjects = {}
    shutdown = False
    
    def __init__(self, name, **args):
        fromServer = args.pop('fromServer',False)
        if fromServer:
            self.name = name
        else:
            self.name = networkServer.makeObjectName(name)
            
        self.allObjects[self.name] = self
        
        self.vars = {}
        self.actions = {}
        
        self.loadFunctions = util.getFunctions(self,"load_")
        self.load(args)
        
    def load(self, args):
        for key, vals in args.iteritems():
            assert key in self.loadFunctions, "unknown file tag %s" % key
            self.loadFunctions[key](vals)
            
    def loadFile(self, filename):
        self.load(yaml.evalLoad(open(fileServer.getFile(filename))))
            
    def load_vars(self, vals):
        for name, val in vals.iteritems():
            self.setVar(name,val)
            
    def load_include(self, vals):
        self.loadFile(vals)
            
    def load_includes(self, vals):
        map(self.loadFile,vals)
        
    def load_actions(self, vals):
        for actionName, actionVals in vals.iteritems():
            actionType = actionVals.pop('type',actionName)
            self.runAction(actionType,actionName,**actionVals)
            
    def distSetVar(self, name, val):
        self.vars[name] = val
        networkServer.distSetVar(self.name,name,val)
            
    def setVar(self, name, val):
        self.vars[name] = val
        networkServer.setVar(self.name,name,val)
        
    def getVar(self, name, default):
        self.requestVar(name)
        if name in self.vars:
            return self.vars[name]
        else:
            return default
        
    def hasVar(self, name):
        self.requestVar(name)
        return name in self.vars
    
    def requestVar(self, name):
        networkServer.requestVar(self.name,name)
        
    def runAction(self, actionType, actionName = None, **args):
        return networkServer.runAction(self.name,actionType,actionName,args)
        
    def doRunAction(self, actionType, actionName, args):
        actionClass = util.dynload(actionType)
        assert actionClass, "unknown actionType %s" % actionType
        assert issubclass(actionClass,Action), "action type %s isn't inherited from action" % actionType
        action = actionClass(actionName,self)
        self.actions[actionName] = action
        action.run(args)
        return action
    
    def hasAction(self, actionName):
        return actionName in self.actions
    
    def getAction(self, actionName):
        assert actionName in self.actions, "no action %s in object %s" % (actionName, self.name)
        return self.actions[actionName]
    
    def deferRpc(self, actionName, cmd, **args):
        return networkServer.rpc(self.name,actionName,cmd,args)
    
    def callRpc(self, actionName, cmd, **args):
        return self.deferRpc(actionName,cmd,**args)()
    
    def stopAction(self, actionName):
        assert actionName in self.actions, "can't stop unknown action %s" % actionName
        action = self.actions.pop(actionName)
        action.stop()
        
    def stopAllActions(self):
        for action in self.actions.itervalues():
            action.stop()
        self.actions.clear()
        
    def delete(self, tellServer = True):
        self.doDelete()
        if tellServer:
            networkServer.deleteObject(self.name)
        
    def doDelete(self):
        self.log("delete")
        self.stopAllActions()
        self.allObjects.pop(self.name)
        
    @staticmethod
    def runAll():
        try:
            fileServer.loadModules()
            networkServer.connect()
            fileServer.loadFiles()
            
            numFrames = 0
            start = time.time()
            while not Object.shutdown:
                numFrames += 1
                eventServer.localPublish("update", time = time.time() - start)
            runTime = time.time() - start
            print "%d frames in %f secs = %f fps" % (numFrames, runTime, float(numFrames) / runTime)
        finally:
            Object.deleteAll()
            networkServer.kill()
            
    @classmethod
    def shutdownAll(self):
        Object.shutdown = True
            
    @staticmethod
    def deleteAll():
        print "deleteAll"
        for object in Object.allObjects.values():
            object.delete(False)
        Object.allObjects.clear()
        
    @classmethod
    def hasObject(self, name):
        return name in self.allObjects
    
    @classmethod
    def getObject(self, name):
        assert name in self.allObjects, "can't get unknown object %s" % name
        return self.allObjects[name]
    
    @classmethod
    def deleteObject(self, name, tellServer = True):
        assert name in self.allObjects, "can't delete unknown object %s" % name
        self.allObjects.pop(name).delete(tellServer)
    
    @classmethod
    def search(self, cond):
        for object in self.allObjects.itervalues():
            if cond(object):
                return object
            
    @classmethod
    def searchAll(self, cond):
        return filter(cond,self.allObjects.values())
    
    def log(self, *v):
        print "%s: %s" % (self.name, ' '.join(map(str,v)))
        
from fileServer import fileServer
from networkServer import networkServer
from optionServer import optionServer
from timeServer import timeServer
